/**
 * Project Name:jiuselu-parent
 * File Name:PayController.java
 * Package Name:com.fxp.project.jiuselu.web.business.v1.controller.pay
 * Date:2021年12月26日 11:48
 * Copyright (c) 2021, Jason.Wang All Rights Reserved.
 */
package com.fxp.project.jiuselu.web.business.v1.controller.pay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fxp.project.jiuselu.web.base.controller.BaseController;
import com.fxp.project.jiuselu.web.business.v1.request.order.ReqOrderDetail;
import com.fxp.project.jiuselu.web.config.YopOprConstants;
import com.fxp.project.jiuselu.web.domain.CommonResult;
import com.fxp.project.jiuselu.web.models.order.entity.JslOrderArrears;
import com.fxp.project.jiuselu.web.models.order.service.IJslOrderArrearsService;
import com.fxp.project.jiuselu.web.models.order.service.IJslOrderService;
import com.fxp.project.jiuselu.web.models.order.vo.JslOrderVo;
import com.fxp.project.jiuselu.web.models.user.entity.JslUserOauth;
import com.fxp.project.jiuselu.web.models.user.service.IJslUserOauthService;
import com.yeepay.yop.sdk.exception.YopClientException;
import com.yeepay.yop.sdk.model.YopRequestConfig;
import com.yeepay.yop.sdk.service.common.YopClient;
import com.yeepay.yop.sdk.service.common.YopClientBuilder;
import com.yeepay.yop.sdk.service.common.request.YopRequest;
import com.yeepay.yop.sdk.service.common.response.YopResponse;
import com.yeepay.yop.sdk.service.sys.SysClient;
import com.yeepay.yop.sdk.service.sys.SysClientBuilder;
import com.yeepay.yop.sdk.service.sys.request.TradeOrderRequest;
import com.yeepay.yop.sdk.service.sys.request.TradeRefundRequest;
import com.yeepay.yop.sdk.service.sys.response.TradeOrderResponse;
import com.yeepay.yop.sdk.service.sys.response.TradeRefundResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

/**
 * ClassName:PayController<br/>
 * Function: 支付订单信息<br/>
 * Date:2021年12月26日 11:48<br/>
 *
 * @author Jason.Wang
 * @version 1.0.0
 * @see
 * @since JDK 1.8
 */
@RestController
@RequestMapping("/v1/pay")
public class PayController extends BaseController {

    /**
     * 该Client线程安全，请使用单例模式，多次请求共用
     */
    private static final SysClient sysClient = SysClientBuilder.builder().build();


    @Autowired
    IJslOrderService jslOrderService;
    @Autowired
    private YopOprConstants yopOprConstants;
    @Autowired
    IJslUserOauthService jslUserOauthService;
    @Autowired
    IJslOrderArrearsService jslOrderArrearsService;

    // 该Client线程安全，请使用单例模式，多次请求共用
    private static final SysClient api = SysClientBuilder.builder().build();

    /**
     * payment: 提交支付信息<br/>
     *
     * @param reqOrderDetail
     * @param result
     * @return
     * @author Jason.Wang
     * @date 2021/12/26 12:28
     */
    @PostMapping("payment")
    @CrossOrigin
    public CommonResult payment(@RequestBody @Validated ReqOrderDetail reqOrderDetail, BindingResult result) {
        System.err.println("reqOrderDetail.getPayType() = " + reqOrderDetail.getPayType());
        super.checkBindResult(result);
        // 查询当前用户的订单信息
        JslOrderVo jslOrderVo = jslOrderService.selectJslOrderVoByUserIdAndOrderId(reqOrderDetail.getOrderId(), super.getCurrentUserInfo().getUserId());
        // 判断当前订单信息的支付状态
        if (null == jslOrderVo) {
            return CommonResult.failed("订单不存在");
        }
        if (null != jslOrderVo.getPayStatus() && jslOrderVo.getPayStatus() == 1) {
            return CommonResult.failed("该订单已经完成支付");
        }
        JSONObject goodsInfo = new JSONObject();
        goodsInfo.put("goodsName", jslOrderVo.getOrderGoodsList().get(0).getGoodsAttrName());
        goodsInfo.put("goodsDesc", jslOrderVo.getOrderGoodsList().get(0).getGoodsName());

        JSONObject memoInfo = new JSONObject();
        memoInfo.put("orderId", jslOrderVo.getOrderId());
        memoInfo.put("orderType", jslOrderVo.getOrderType());

        // 查询当前订单是什么订单类型
        String orderAmount = "";
        String arrearsId = null;
        switch (jslOrderVo.getOrderType()) {
            case 0:
                arrearsId = String.format("%s%s", jslOrderVo.getOrderId(), "1");
                break;
            case 1:
                if (jslOrderVo.getPayStatus() == 0) {
                    arrearsId = String.format("%s%s", jslOrderVo.getOrderId(), "1");
                } else {
                    arrearsId = String.format("%s%s", jslOrderVo.getOrderId(), "2");
                }
                break;
            case 5: {
                arrearsId = String.format("%s%s", jslOrderVo.getOrderId(), "1");
                break;
            }
            case 6: {
                arrearsId = String.format("%s%s", jslOrderVo.getOrderId(), "1");
                break;
            }
            default:
                return CommonResult.failed("该订单已经完成支付");
        }
        JslOrderArrears jslOrderArrears = jslOrderArrearsService.getById(arrearsId);
        if (null == jslOrderArrears) {
            return CommonResult.failed("当前订单付款信息不存在");
        }
        orderAmount = jslOrderArrears.getArrearsAmount().toString();
        TradeOrderResponse tradeOrderResponse = createOrder(arrearsId, orderAmount, goodsInfo, memoInfo);

        if (null == tradeOrderResponse) {
            return CommonResult.failed("支付下单创建失败，请联系客服");
        }

        String payType = "WECHAT";
        String payTool = "SCCANPAY";
        String token = tradeOrderResponse.getResult().getToken();

        if (StringUtils.isBlank(token)) {
            return CommonResult.failed(tradeOrderResponse.getResult().getMessage());
        }

        // 判断用户选择的是什么支付类型
        switch (reqOrderDetail.getPayType()) {
            case 1:
                payType = "ALIPAY";
                break;
            default:
                payType = "WECHAT";
                break;
        }
        String appId = "";
        String openId = "";
        if (4 == reqOrderDetail.getPlatform()) {
            payTool = "MINI_PROGRAM";
            payType = "WECHAT";
            appId = yopOprConstants.getXcxAppId();
//            if (StringUtils.isBlank(openId) && StringUtils.isBlank(reqOrderDetail.getOpenId())) {
//                appId = yopOprConstants.getXcxAppId();
//                QueryWrapper<JslUserOauth> queryWrapper = new QueryWrapper<>();
//                queryWrapper.eq("user_id", super.getCurrentUserInfo().getUserId());
//                queryWrapper.eq("oauth_type", 1);
//                queryWrapper.eq("oauth", 0);
//                JslUserOauth jslUserOauth = jslUserOauthService.getOne(queryWrapper);
//                if (null != jslUserOauth) {
//                    openId = jslUserOauth.getOpenid();
//                } else {
//                    return CommonResult.failed("支付下单创建失败，缺失OpenId");
//                }
//            } else {
//                openId = reqOrderDetail.getOpenId();
//            }
            if (StringUtils.isBlank(openId) && StringUtils.isBlank(reqOrderDetail.getOpenId())) {
                appId = yopOprConstants.getXcxAppId();
                QueryWrapper<JslUserOauth> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("user_id", super.getCurrentUserInfo().getUserId());
                queryWrapper.eq("oauth", 0);
                List<JslUserOauth> jslUserOauth = jslUserOauthService.list(queryWrapper);
                if (jslUserOauth.size() == 0) {
                    return CommonResult.failed("请绑定微信");
                }
                for (JslUserOauth oauth : jslUserOauth) {
                    if (oauth.getOpenid() != null) {
                        openId = oauth.getOpenid();
                        break;
                    }
                }


            } else {
                openId = reqOrderDetail.getOpenId();
            }
        } else {
            appId = yopOprConstants.getGzhAppId();
        }

        //微信小程序代付功能传2生成二维码页面
        if (reqOrderDetail.getPayType() == 2) {
            String payTool1 = "SCCANPAY";
            YopResponse response = getPayCode(token, payTool1, payType, appId, openId);
            JSONObject resultJson = JSON.parseObject(response.getStringResult());
            return CommonResult.success(resultJson.getString("resultData"));
        }
//        YopResponse response = getPayCode(token, payTool, payType, appId, openId);
        YopResponse response = getPayCode(token, payTool, payType, appId, openId);
        JSONObject resultJson = JSON.parseObject(response.getStringResult());
        return CommonResult.success(resultJson.getString("resultData"));
    }

    /**
     * payment: 提交退款信息<br/>
     *
     * @param reqOrderDetail
     * @param result
     * @return
     * @author Jason.Wang
     * @date 2021/12/26 12:28
     */
    @PostMapping("refund")
    @CrossOrigin
    public CommonResult refund(@RequestBody @Validated ReqOrderDetail reqOrderDetail, BindingResult result) {
        System.err.println("reqOrderDetail.getPayType() = " + reqOrderDetail.getPayType());
        super.checkBindResult(result);
        // 查询当前用户的订单信息
        try {
            JslOrderVo jslOrderVo = jslOrderService.selectJslOrderVoByUserIdAndOrderId(reqOrderDetail.getOrderId(), super.getCurrentUserInfo().getUserId());
            // 判断当前订单信息的支付状态
            if (null == jslOrderVo) {
                return CommonResult.failed("订单不存在");
            }
            if (jslOrderVo.getPayStatus() == 1) {
                JslOrderArrears one = jslOrderArrearsService.getOne(new QueryWrapper<JslOrderArrears>().eq("order_id", jslOrderVo.getOrderId())
                        .eq("pay_status", 1));
                if (Optional.ofNullable(one).isPresent()) {
                    TradeRefundRequest request = new TradeRefundRequest();
                    request.setParentMerchantNo(yopOprConstants.getMerchantNo());
                    request.setMerchantNo(yopOprConstants.getSubMerchantNo());
                    request.setRefundRequestId("TK" + one.getArrearsId().substring(2));
                    request.setRefundAmount("0.01");
                    request.setDescription("用户退款");
                    request.setParentMerchantNo(yopOprConstants.getMerchantNo());
                    request.setMerchantNo(yopOprConstants.getSubMerchantNo());
                    request.setOrderId(one.getArrearsId());
                    request.setUniqueOrderNo(one.getTransactionId());
                    TradeRefundResponse response = sysClient.tradeRefund(request);
                    System.out.println(response.getResult());
                    return CommonResult.success(response.getResult().getMessage());
                }
            }
        } catch (YopClientException e) {
            System.err.println("Exception when calling SysClient#tradeRefund, ex:" + e);
        }
        return CommonResult.success("");
    }


    /**
     * createOrder: 创建当前支付前的订单信息<br/>
     *
     * @param arrearsId
     * @param orderAmount
     * @param goodsInfo
     * @param memoInfo
     * @return
     * @throws IOException
     * @author Jason.Wang
     * @date 2021/12/26 16:58
     */
    private TradeOrderResponse createOrder(String arrearsId, String orderAmount, JSONObject goodsInfo, JSONObject memoInfo) {
        return creteOrder(arrearsId, orderAmount, goodsInfo, memoInfo);
    }

    public static void main(String[] args) {
//        String arrearsId="QK202204191611145595591061";
//        String orderAmount="200.00";
//        JSONObject goodsInfo=new JSONObject();
//        goodsInfo.put("goodsName","200");
//        goodsInfo.put("goodsDesc","黑5");
//        JSONObject memoInfo=new JSONObject();
//        memoInfo.put("orderType",1);
//        memoInfo.put("orderId","orderId -> QK20220419161114559559106");
        TradeRefundRequest request = new TradeRefundRequest();
        request.setParentMerchantNo("10034133336");
        request.setMerchantNo("10034274377");
        request.setOrderId("QK20220512160411967967210");
        request.setRefundRequestId(UUID.randomUUID().toString());
        request.setUniqueOrderNo("1001201612070000000000000565");
        request.setRefundAmount("88.88");
        request.setAccountDivided("[{\"ledgerNo\":\"10000466921\",\"amount\":0.01,\"ledgerName\":\"test@yeepay.com”},&nbsp;&nbsp;{\"ledgerNo\":\"10012426766\",\"amount\":0.01,\"ledgerName\":\"test@yeepay.com\"}]注意：收单方承担的金额也要写有JOSN串里，JSON里的金额总和等于退款金额");
        request.setDescription("用户退货退款");
        request.setMemo("memo_example");
        request.setNotifyUrl("notifyUrl_example");
        request.setHmac("hmac_example");
        request.setMerchantSideMarketingRefundDetails("merchantSideMarketingRefundDetails_example");
        request.setRefundAccountType("FUND_ACCOUNT");
        try {
            TradeRefundResponse response = api.tradeRefund(request);
            System.err.println("result:{}" + response.getResult());
        } catch (YopClientException e) {
            System.err.println("Exception when calling SysClient#tradeRefund, ex:" + e);
        }


    }

    public static String doGet(String httpUrl, Map<String, Object> map, String type) {
        HttpURLConnection connection = null;
        OutputStream os = null;
        InputStream is = null;
        BufferedReader br = null;
        StringBuilder result = new StringBuilder();
        try {
            URL url = new URL(httpUrl);
            connection = (HttpURLConnection) url.openConnection();
//            connection.setRequestMethod("POST");
            connection.setRequestMethod(type);
            connection.setReadTimeout(10000);
            connection.setDoOutput(true);
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            connection.setRequestProperty("content-Type", "application/json;charset=utf-8");

            //拼接请求参数
            os = connection.getOutputStream();

            JSONObject json = new JSONObject();
            for (String s : map.keySet()) {
                json.put(s, map.get(s));
            }

//            os.write(transform(map).getBytes());
            os.write(json.toString().getBytes());

            //开始连接
            connection.connect();

            //读取响应
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                if (null != is) {
                    br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
                    String temp = null;
                    while (null != (temp = br.readLine())) {
                        result.append(temp);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
                if (is != null) {
                    is.close();
                }

            } catch (IOException ioException) {
                ioException.printStackTrace();
            }

            assert connection != null;
            connection.disconnect();
        }
        return result.toString();
    }

    public TradeOrderResponse creteOrder(String arrearsId, String orderAmount, JSONObject goodsInfo, JSONObject memoInfo) {
        TradeOrderRequest request = new TradeOrderRequest();
        request.setParentMerchantNo(yopOprConstants.getMerchantNo());
        request.setMerchantNo(yopOprConstants.getSubMerchantNo());
        request.setOrderId(arrearsId);
        //真实金额
        request.setOrderAmount(orderAmount);
//        request.setOrderAmount("0.01");
//        request.setTimeoutExpress(30);
        // SECOND("秒"), MINUTE("分"), HOUR("时"), DAY("天")
        request.setTimeoutExpressType("MINUTE");
//        request.setRequestDate("2017-12-12 13:23:45");
        // 页面跳转地址，同步跳转的 后续配置
        request.setRedirectUrl(yopOprConstants.getCallbackUrl());
        // 异步通知地址
        request.setNotifyUrl(yopOprConstants.getNotifyUrl());
//        request.setAssureType("REALTIME");
//        request.setAssurePeriod("assurePeriod_example");
        request.setGoodsParamExt(goodsInfo.toJSONString());
//        request.setPaymentParamExt("paymentParamExt_example");
//        request.setIndustryParamExt("industryParamExt_example");
//        request.setRiskParamExt("riskParamExt_example");
        request.setMemo(memoInfo.toJSONString());
//        request.setFundProcessType("fundProcessType_example");
//        request.setHmac("hmac_example");
//        request.setDivideDetail("divideDetail_example");
//        request.setCsUrl("csUrl_example");
//        request.setDivideNotifyUrl("divideNotifyUrl_example");
//        request.setTimeoutNotifyUrl("timeoutNotifyUrl_example");
//        request.setSiSubsidyMerchantAmout("siSubsidyMerchantAmout_example");
//        request.setQueryParamsExt("queryParamsExt_example");
        try {
            TradeOrderResponse response = sysClient.tradeOrder(request);
            System.out.println(response.getResult());
            return response;
        } catch (YopClientException e) {
            System.err.println("Exception when calling SysClient#tradeOrder");
            e.printStackTrace();
        }
        return null;
    }


    /**
     * getPayCode: 获取支付码<br/>
     *
     * @param token
     * @param payTool
     * @param payType
     * @param appId
     * @param openId
     * @return
     * @author Jason.Wang
     * @date 2021/12/26 17:03
     */
    private YopResponse getPayCode(String token, String payTool, String payType, String appId, String openId) {
        YopClient yopClient = YopClientBuilder.builder().build();
        // 指定要请求的API地址和请求方式
        YopRequest request = new YopRequest(YopOprConstants.PAY_LINK_ORDER_API, "POST");
        YopRequestConfig requestConfig = request.getRequestConfig();
        // 请求级别appkey设置(可选)，否则取默认appKey
        requestConfig.setAppKey(yopOprConstants.getAppKey());
        // 配置安全需求(可选)，在当前应用支持的安全需求做选择
        requestConfig.setSecurityReq("YOP-SM2-SM3");
        // 指定单次请求获取数据的超时时间, 单位：ms(可选，默认采用配置文件中的设置)
        requestConfig.setReadTimeout(3000);
        // 指定单次请求建立连接的超时, 单位：ms(可选，默认采用配置文件中的设置)
        requestConfig.setConnectTimeout(3000);
        // 普通参数传递
        // step2.配置参数
        request.addParameter("payTool", payTool);
        request.addParameter("payType", payType);
        request.addParameter("token", token);
        if (StringUtils.isNotBlank(appId)) {
            request.addParameter("appId", appId);
        }
        if (StringUtils.isNotBlank(openId)) {
            request.addParameter("openId", openId);
        }
        request.addParameter("userIp", yopOprConstants.getUserIp());
        request.addParameter("extParamMap", "{\"reportFee\":\"XIANXIA\"}");
        YopResponse response = null;
        try {
            // 如果是：普通请求
            response = yopClient.request(request);
        } catch (YopClientException e) {
            e.printStackTrace();
        }
        return response;
    }


}
